/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 *
 * $Id: ImageClient.hpp,v 1.10 2009-05-13 07:18:17 amaula Exp $
 *
 * \file
 * \brief MaCI - Image Interface Client header
 * \author Antti Maula <antti.maula@tkk.fi>
 */
#ifndef _MACI_INTERFACE_IMAGECLIENT_HPP_
#define _MACI_INTERFACE_IMAGECLIENT_HPP_

#include "MaCI.hpp"
#include "thread.hpp"
#include "sync.hpp"

// These are not necessarily required here, but defined to make the
// interface easier to include.
#include "ImageData.hpp"
#include "ImageContainer.hpp"


// Forward declare gimi::GIMI
namespace gimi {
  class GIMI;
}

namespace MaCI {
  namespace Image {
    
    // Forward declarations.
    class CImageData;
    class CImageClient;


    /** Callback interface class for Image interface.
     *
     * This interface defines functions which can be used for
     * ImageClient callbacks. These functions are executed (more
     * detail per function basis) as new data arrives, and directly
     * from the context of the receiving thread. <b>Therefore, it is
     * important that the handling function is as simple and fast as
     * possible, as it will block the execution of the receiving
     * thread while executed.</b>
     */
    class CImageClientCallback
    {
    public:

      CImageClientCallback() {}
      virtual ~CImageClientCallback() {}


      /** Handler function for ImageData event.
       *
       * This function is called when the ImageClient receives new
       * data from the server.
       *
       * \note <b>Keep this function simple & fast as it will block the 
       * data receiving thread while executing!</b>
       *
       * @param[in] aData       Constant reference to CImageData element 
       *                        containing the received event.
       * @param[in] aDataSequence Sequence number of the received data. 
       *                        This should increment by one on each call.
       * @param[in] aImageClient Reference to ImageClient 
       *                        instance which received this event.
       */
      virtual void OnImageDataEvent(const CImageData &aData, 
                                    const unsigned int aDataSequence,
                                    CImageClient &aImageClient) = 0;
    };


    /** MaCI - Image Client interface.
     * 
     * This class contains the methods and types for using
     * a MaCI::Image service in the GIMnet.
     */
    class CImageClient : private gim::CSync,
                         private gim::CThread,
                         public MaCI::CMaCI
    {
    public:
      /** Constructor.
       * 
       * Constructor of the ImageClient. This requires;
       * a pointer to Initialized and connected GIMI, minor
       * number of this interface (Used as GIMI minor number)
       *
       * @param[in] aGIMIPtr Pointer to GIMI used for communication
       * @param[in] aInterfaceMinor Interface minor number. Usually
       *            used to indicate the instance of devices of same
       *            type.
       */     
      CImageClient(gimi::GIMI *aGIMIPtr, const int aInterfaceMinor = -1);

      
      /** Destructor.
       */
      ~CImageClient();



      /** Receive Image data elements.
       *
       * This function returns CImageData elements sent from the
       * service side of the interface. All data is packaged inside
       * the CImageData container. Last received image is stored
       * inside this ImageClient instance, so calling GetImageData
       * multiple times with same parameters will always return the
       * same image.
       *
       * @param[out] aImgData   Qualified CImageData element is stored
       *                        to this reference on succesfull call.
       * @param[in] aImgSeq     Pointer to imagesequence number.
       *                        If this is set to NULL, the function will
       *                        return the last received image immediately.
       *                        If this is not NULL, the value pointed
       *                        should be set to 0 on the first call to this 
       *                        function. After each call the sequence number 
       *                        of the returned scan is stored here. If user 
       *                        wants to read all images available in sequence 
       *                        then this value should not be modified by user 
       *                        after the first call. Default value is NULL.
       * @param[in] aTimeout_ms Timeout in milliseconds to wait for
       *                        the operation to succeed. If no image was
       *                        received during the timeout, error is returned.
       *                        Default timeout is 1000ms.
       * @return                'true' in case an image was succesfully stored
       *                        on the provided reference. 'false' on any error,
       *                        including case 'no images available' and 
       *                        'timeout'.
       */
      bool GetImageData(CImageData &aImgData, 
                        unsigned int *aImgSeq = NULL,
                        const unsigned int aTimeout_ms = 1000);


      /** Get SourceInfoMap from Server (or use local copy if available)
       * 
       * This function returns all SourceInfo elements available on
       * the Server interface. SourceInfo elements are used to
       * describe the camera sources in a way they should be both
       * machine and human parseable. See the structure TSourceInfo.
       * This function fetches the information directly from the
       * ImageServer instance, unless the information is already
       * available. To force a refresh on SourceInfoMap, user may use
       * the 'aRefresh' parameter.
       *
       * \see GetSourceInfo
       *
       * @param[out] aMap       SourceInfo elements are stored in this 
       *                        std::map container
       * @param[in] aTimeout_ms Timeout in milliseconds to wait for 
       *                        the operation to complete.
       * @param[in] aRefresh    Force refresh. This forces the function to
       *                        refetch the information from the remote
       *                        end even the information would already be
       *                        stored inside the client instance.
       * @return                'true' when the source map was succesfully
       *                        received and stored to given reference. Note
       *                        that the map may still be empty if the 
       *                        server user hasn't specified any descriptions.
       *                        'false' in case interrogating the remote
       *                        end failed, and we had no local copy or
       *                        refresh flag was set.
       */
      bool GetSourceInfoMap(TSourceInfoMap &aMap, 
                            const unsigned int aTimeout_ms = 2000, 
                            const bool aRefresh = false);
      
      
      /** Get SourceInfo from Server (or use local copy if available)
       *
       * This function is otherwise identical to the
       * 'GetSourceInfoMap()' function, except that it returns one
       * TSouceInfo entry keyed by Image index (Corresponds, or SHOULD
       * correspond to the 'sourceindex' field in the CImageData
       * container)
       *
       * @param[out] aInfo      Information about the requested index is
       *                        stored here.
       * @param[in] aIndex      Image sourceindex to request SourceInfo for.
       * @param[in] aTimeout_ms Timeout in milliseconds to wait for 
       *                        the operation to complete.
       * @param[in] aRefresh    Force refresh. This forces the function to
       *                        refetch the information from the remote
       *                        end even the information would already be
       *                        stored inside the client instance.
       * @return                'true' when the source map was succesfully
       *                        received and stored to given reference. Note
       *                        that the map may still be empty if the 
       *                        server user hasn't specified any descriptions.
       *                        'false' in case interrogating the remote
       *                        end failed, and we had no local copy or
       *                        refresh flag was set.
       */
      bool GetSourceInfo(TSourceInfo &aInfo, 
                         const unsigned int aIndex, 
                         const unsigned int aTimeout_ms = 2000, 
                         const bool aRefresh = false);
      
      /** Assigns the Image client callback function. 
       *
       * This sets a function object for calling a image client
       * callback. If this is set, the interface calls the assigned
       * functions immediately when event is available.
       * 
       * \note As the function is run in the context of the receiving
       * thread, user must make sure that the callback function is
       * fast. As if the function executes too long, receiving events
       * is interrupted.
       *
       * @param[in] aImageClientCallback Pointer to class implementing the interface
       *                                 CImageClientCallback.
       */
      void SetImageClientCallback(CImageClientCallback *aImageClientCallback) {
        iImageClientCallback = aImageClientCallback;
      }
      
    protected:
      /** Open client interface.
       */
      EMaCIError DoOpen(void);
      
      
      /** Close client interface.
       */
      EMaCIError DoClose(void);


    private:
      /** Enumeration for handling Wait() events.
       */
      enum EImageEvent { 
        KEventNewImage = 0,      ///< New image received.
        KEventSourceInfoMap = 1  ///< New SourceInfo received.
      };

      /// Thread runner function. Is in charge of receiving events.
      int ThreadFunction(const int aThreadNumber);
      int ProcessMessage(const gimi::GIMIMessage &msg);

      //data.
      unsigned int iImageSequence;
      CImageData iLastImageData;

      TSourceInfoMap iSourceInfoMap; ///< Source info map.
      bool iSourceInfoMapReceived; ///< Flag to mark whether map is received (because empty map is also valid)

      CImageClientCallback *iImageClientCallback;

      // Funcs.
      CImageClient(const CImageClient &)
        : CSync(2,1),
          CThread(1),
          CMaCI(NULL, GIMI_PROTOCOL_MACI_IMAGE, 0, ""),
          iImageSequence(0),
          iLastImageData(),
          iSourceInfoMap(),
          iSourceInfoMapReceived(false),
          iImageClientCallback(NULL) {}
      CImageClient &operator=(const CImageClient &) { return *this; }

    };


  }
}

#endif //_MACI_INTERFACE_IMAGECLIENT_HPP_
